from ev import utils
from game.gamesrc.objects.room import MyRoom
from game.gamesrc.wild.commands import CmdSetWild
from game.gamesrc.utils import myutils

class Wilderness(MyRoom):
    """
    This class implements a simple wilderness system.
    """

    def at_object_creation(self):
        super(Wilderness, self).at_object_creation()
        self.locks.add("call:true();get:false();puppet:false()") # would be weird to puppet a wilderness ...
        self.db.location = None
        self.db.layers = []
        self.db.desc = ""
        self.db.flags.append('WILD')
        self.db.fallback_loc = (0,0)
        self.cmdset.add_default(CmdSetWild, permanent=True)
        self.db.x_lenght = 0
        self.db.y_lenght = 0

    def at_object_leave(self, moved_obj, target_location):
        """
        Called just before an object leaves from inside this object

        moved_obj - the object leaving
        target_location - where the object is going.
        
        This is needed to clear wild_loc attribute on objects leaving the wilderness.
        """
        moved_obj.db.wild_loc = (None, None)

    def at_object_receive(self, obj, source_location):
        """
        Set a default wild_loc when an object arrives here without one.
        """
        if obj.db.wild_loc == (None, None):
            obj.db.wild_loc = self.db.fallback_loc

    def access(self, accessing_obj, access_type='read', wild_loc=None, default=False):
        """
        Determines if another object has permission to access a cell of this wilderness
        or the wilderness itself (in this case left wild_loc=None).

          accessing_obj (Object)- object trying to access this one
          access_type (string) - type of access sought
          wild_loc (tuple) - x, y coordinates in the wilderness
          default (bool) - what to return if no lock of access_type was found
        """
        if not wild_loc:
            # if not wild_lock, check the access on the whole wilderness (basically a single room)
            return self.dbobj.access(accessing_obj, access_type=access_type, default=default)
        locks = self.layers.get('locks', None)
        if not locks:
            return True
        lockstrings = locks.get(wild_loc)
        if not lockstrings:
            return True
        lockstrings = lockstrings.split(" ")
        for lockstring in lockstrings:
            if access_type in lockstring:
                return self.locks.check_lockstring(accessing_obj, lockstring, no_superuser_bypass=False)
        return True

    def return_appearance(self, pobject):
        """
        This is a convenient hook for a 'look'
        command to call.
        """
        if not pobject:
            return
        pos = pobject.wild_loc
        # name
        name = "{cWilderness{n"
        names = self.db.layers.get('name')
        if names:
            name = names.get(pos)
        string = "{c%s{n" % name.capitalize()
        # map
        mobs = [element.wild_loc for element in self.contents if element.has_player or (hasattr(element, "is_mob") and element.is_mob)]
        for y in range(pos[1]-4, pos[1]+5):
            if 0 <= y < self.y_lenght:
                string += "\n"
                for x in range(pos[0]-4, pos[0]+5):
                    if 0 <= x < self.x_lenght:
                        if (x, y) == pos:
                            string += "{R@{n"
                            continue
                        if (x, y) in mobs:
                            string += "{M@{n"
                            continue
                        color = 'n'
                        colors = self.db.layers.get('colors')
                        if colors:
                            color = colors.get((x,y))
                        if not color: color = 'n'
                        string += "{%s%s{n" % (color, self.db.wild[y][x])
                    else:
                        string += " "
            else:
                string += "\n"
        # desc
        descs = self.db.layers.get('desc')
        if descs:
            desc = descs.get(pos)
        #desc = self.attr('desc') # you can add a global description with this
        #if desc:
        #    desc = utils.fill(desc)
        #    string += "\n %s" % desc

        obj_list = filter(lambda x: hasattr(x, "wild_loc") and x.wild_loc == pobject.wild_loc, self.contents)

        exits = []
        users = []
        things = []
        cols = [[],[]]
        for content in [con for con in obj_list if con.access(pobject, 'view')]:
            if content == pobject:
                continue
            if content.destination: # exits
                if hasattr(content, "is_closed") and content.is_closed:
                    cols[0].append(content.name)
                    cols[1].append(content.db.door_name.capitalize())
                    continue           
                if hasattr(content.destination, "is_dark") and content.destination.is_dark:
                    cols[0].append(content.name)
                    cols[1].append("E' molto buio qui...")
                    continue      
                cols[0].append(content.name)
                cols[1].append(content.destination.name.capitalize())
            elif content.has_player: # players
                users.append(content.name)
            else: # things
                things.append(content.r_desc)

        things = list(myutils.tile_objects(things))


        if cols[0]:
            ftable = utils.format_table(cols)
            string += "\n{wUscite:{n"
            for row in ftable:
                string += "\n " + "%s- %s" % (row[0], row[1])
        if users or things:
            string += "\n{wStai vedendo:\n{n"
            if users:
                string += "{c" + "\n".join(users) + "{n\n"
            if things:
                string += "\n".join(things)
        return string

    def msg_contents(self, message, exclude=None, from_obj=None, data=None, obj_list=None, wild_loc=None):
        """
        Emits something to all objects inside an object.

        exclude is a list of objects not to send to. See self.msg() for more info.

        """
        wild_exclude = filter(lambda x: x.db.wild_loc != wild_loc, self.contents)
        if exclude:
            exclude = utils.make_iter(exclude)
            exclude.extend(wild_exclude)
        else:
            exclude = wild_exclude
        super(Wilderness, self).msg_contents(message, exclude=exclude, from_obj=from_obj, data=data, obj_list=obj_list, wild_loc=wild_loc)


class WildLayer(object):

    def __init__(self, name, filename=None):
        self.key = name
        self.priority = 0
        self.map = []
        self.consts = {}
        self.vars = {}
        if filename:
            self.load(filename)

    def load_map(self, filename):
        """
        This method loads lines saved in a txt file. The file is parsed
        and lines beginning with '/' or '#' are ignored, everything else
        is loaded as a part of the resulting map. This is useful if you
        just want to load a map to display, without declared variables
        in it.
        """
        map_ = []
        try:
            with open(filename) as file_:
                for line in file_:
                    line = line.strip()
                    if not line or line[0] == "#" or line[0] == "/":
                        continue
                    map_.append(line.strip().split("\n", 1)[0])
        except:
            pass
        self.filename = filename
        self.map = map_

    def load(self, filename):
        """
        This method reads a txt file to load a "map" and search for
        variables defined in it. The loaded map and variables are stored
        on the layer object. You'll need to launch this function after 
        __init__() for the layer to work properly.
        """

        map_ = []
        consts = {}
        try:
            with open(filename) as file_:
                for line in file_:
                    line = line.strip()
                    if not line or line[0] == "#": continue
                    if line[0] == "/":
                        key, value = line[1:].split("=", 1)
                        consts[key.strip()] = value.split("\n", 1)[0].strip()
                        continue
                    map_.append(line.strip().split("\n", 1)[0])
        except:
            pass
        self.filename = filename
        self.map = map_
        self.consts = consts

    def _reload(self):
        if not self.filename:
            return
        else:
            self.load(self.filename)

    def get(self, xy):
        if xy in self.vars:
            return self.vars.get(xy, "")
        else:
            return self.consts.get(self.map[xy[1]][xy[0]], "")
        


    def __str__(self):
        return "%s" % self.key

                

